`include "macro.v"
module top (
    input wire clk_in,
    input wire rst,
    input  wire [23:0] device_switch,
    output wire [23:0] device_led,
    output wire [7:0] led_en,
    output wire led_ca,
	output wire led_cb,
    output wire led_cc,
	output wire led_cd,
	output wire led_ce,
	output wire led_cf,
	output wire led_cg,
	output wire led_dp
    // output wire        debug_wb_have_inst,
    // output wire [31:0] debug_wb_pc,          
    // output wire        debug_wb_ena,         
    // output wire [4:0]  debug_wb_reg,         
    // output wire [31:0] debug_wb_value        
);
wire rst_n = ~rst;
// **********risk_detect**********
wire pause_PC, pause_IF_ID, pause_ID_EX, pause_EX_MEM, pause_MEM_WB;
wire flush_IF_ID, flush_ID_EX, flush_EX_MEM, flush_MEM_WB;
// **********IF**********
// PC
wire [31:0] pc_IF, pc_ID, pc_EX;
wire [31:0] pc4_IF, pc4_ID, pc4_EX, pc4_MEM;
// IROM
wire [31:0] inst_IF, inst_ID;

// **********ID**********
// SEXT
wire [31:0] ext_ID, ext_EX, ext_MEM;
// RF
wire [4:0] wR_EX, wR_MEM, wR_WB;
wire [31:0] rD1_ID, rD1_EX;
wire [31:0] rD2_ID, rD2_EX, rD2_MEM;
// control
wire [3:0] npc_sel_ID, npc_sel_EX;
wire rf_we_ID, rf_we_EX, rf_we_MEM, rf_we_WB;
wire [2:0] sext_op_ID;
wire [1:0] wd_sel_ID, wd_sel_EX, wd_sel_MEM;
wire alua_sel_ID, alua_sel_EX;
wire alub_sel_ID, alub_sel_EX;
wire [3:0] alu_op_ID, alu_op_EX;
wire wen_ID, wen_EX, wen_MEM;
wire [1:0] sd_sel_ID, sd_sel_EX, sd_sel_MEM;
wire [2:0] ld_sel_ID, ld_sel_EX, ld_sel_MEM;

// **********EX**********
// NPC
wire pc_op_EX;
wire [31:0] npc_EX;
// ALU
wire [31:0] alu_c_EX, alu_c_MEM;
wire eq_EX;
wire lt_EX;
wire ltu_EX;

// **********MEM**********
// DRAM
wire [31:0] rd_MEM;

// **********WB**********
wire [31:0] wD_WB;

wire        debug_wb_have_inst;
wire [31:0] debug_wb_pc;          
wire        debug_wb_ena;         
wire [4:0]  debug_wb_reg;         
wire [31:0] debug_wb_value;
wire [31:0] debug_pc_EX, debug_pc_MEM, debug_pc_WB;
wire debug_have_inst_ID, debug_have_inst_EX, debug_have_inst_MEM, debug_have_inst_WB;
assign debug_wb_ena = rf_we_WB;
assign debug_wb_reg = wR_WB;
assign debug_wb_value = wD_WB;
assign debug_wb_pc = debug_pc_WB;
assign debug_wb_have_inst = debug_have_inst_WB;

wire lock;
cpuclk u_cpuclk(
    .clk_in1(clk_in),
    .locked(lock),
    .clk_out1(clk)
);

IO_bridge u_IO_bridge(
    .clk(clk),
    .rst_n(rst_n),
    .addr(alu_c_MEM),
    .wdata(rD2_MEM),
    .wen(wen_MEM),
    .rdata(rd_MEM),
    .sd_sel(sd_sel_MEM),
    .ld_sel(ld_sel_MEM),
    .device_switch(device_switch),
    .device_led(device_led),
    // digital
    .led_en(led_en),
    .led_ca(led_ca),
    .led_cb(led_cb),
    .led_cc(led_cc),
    .led_cd(led_cd),
    .led_ce(led_ce),
    .led_cf(led_cf),
    .led_cg(led_cg),
    .led_dp(led_dp)
);

// **********risk_detect**********
risk_detect u_risk_detect(
    .rR1_ID(inst_ID[19:15]),
    .rR2_ID(inst_ID[24:20]),
    .wR_EX(wR_EX),
    .wR_MEM(wR_MEM),
    .wR_WB(wR_WB),
    .rf_we_EX(rf_we_EX),
    .rf_we_MEM(rf_we_MEM),
    .rf_we_WB(rf_we_WB),
    .pc_op_EX(pc_op_EX),

    .pause_PC(pause_PC),
    .pause_IF_ID(pause_IF_ID),
    .pause_ID_EX(pause_ID_EX),
    .pause_EX_MEM(pause_EX_MEM),
    .pause_MEM_WB(pause_MEM_WB),
    .flush_IF_ID(flush_IF_ID),
    .flush_ID_EX(flush_ID_EX),
    .flush_EX_MEM(flush_EX_MEM),
    .flush_MEM_WB(flush_MEM_WB)
);

// **********IF**********
PC u_pc(
    .clk        (clk),
    .rst_n      (rst_n),
    .pause      (pause_PC),
    .pc_op_i    (pc_op_EX),
    .npc_i      (npc_EX),
    .pc_o       (pc_IF),
    .pc4_o      (pc4_IF)
);

// inst_mem imem(
prgrom u_progrom(
    // .a(pc_IF[31:2]),
    .a(pc_IF[15:2]),
    .spo(inst_IF)
);

IF_ID u_if_id(
    .clk(clk),
    .rst_n(rst_n),
    .pause(pause_IF_ID),
    .flush(flush_IF_ID),

    .pc_i(pc_IF),
    .pc4_i(pc4_IF),
    .inst_i(inst_IF),

    .pc_o(pc_ID),
    .pc4_o(pc4_ID),
    .inst_o(inst_ID)
);

// **********ID**********
SEXT u_sext(
    .sext_op    (sext_op_ID),
    .din        (inst_ID[31:7]),
    .ext        (ext_ID)
);

// wire rf_clk = ~clk;
RF u_rf(
    .clk    (clk),
    .rst_n  (rst_n),
    .rf_we  (rf_we_WB),
    .rR1    (inst_ID[19:15]),
    .rR2    (inst_ID[24:20]),
    .wR     (wR_WB),
    .wD     (wD_WB),
    .rD1    (rD1_ID),
    .rD2    (rD2_ID)
);

control u_control(
    .opcode(inst_ID[6:0]),
    .func7(inst_ID[31:25]),
    .func3(inst_ID[14:12]),
    // .eq(eq),
    // .lt(lt),
    // .ltu(ltu),
    // .npc_op(npc_op_ID),
    .npc_sel(npc_sel_ID),
    .rf_we(rf_we_ID),
    .sext_op(sext_op_ID),
    .wd_sel(wd_sel_ID),
    .alua_sel(alua_sel_ID),
    .alub_sel(alub_sel_ID),
    .alu_op(alu_op_ID),
    .wen(wen_ID),
    .sd_sel(sd_sel_ID),
    .ld_sel(ld_sel_ID),

    .debug_have_inst    (debug_have_inst_ID)
);

ID_EX u_id_ex(
    .clk(clk),
    .rst_n(rst_n),
    .pause(pause_ID_EX),
    .flush(flush_ID_EX),

    .pc_i(pc_ID),
    .pc4_i(pc4_ID),
    .ext_i(ext_ID),
    .rD1_i(rD1_ID),
    .rD2_i(rD2_ID),
    .wR_i(inst_ID[11:7]),
    .npc_sel_i(npc_sel_ID),
    .rf_we_i(rf_we_ID),
    .wd_sel_i(wd_sel_ID),
    .alua_sel_i(alua_sel_ID),
    .alub_sel_i(alub_sel_ID),
    .alu_op_i(alu_op_ID),
    .wen_i(wen_ID),
    .sd_sel_i(sd_sel_ID),
    .ld_sel_i(ld_sel_ID),

    .pc_o(pc_EX),
    .pc4_o(pc4_EX),
    .ext_o(ext_EX),
    .rD1_o(rD1_EX),
    .rD2_o(rD2_EX),
    .wR_o(wR_EX),
    .npc_sel_o(npc_sel_EX),
    .rf_we_o(rf_we_EX),
    .wd_sel_o(wd_sel_EX),
    .alua_sel_o(alua_sel_EX),
    .alub_sel_o(alub_sel_EX),
    .alu_op_o(alu_op_EX),
    .wen_o(wen_EX),
    .sd_sel_o(sd_sel_EX),
    .ld_sel_o(ld_sel_EX),

    .debug_have_inst_i  (debug_have_inst_ID),
    .debug_have_inst_o  (debug_have_inst_EX)
);

// **********EX**********
NPC u_npc(
    .npc_sel_i(npc_sel_EX),
    .eq_i(eq_EX),
    .lt_i(lt_EX),
    .ltu_i(ltu_EX),
    .pc_i(pc_EX),
    .alu_c_i(alu_c_EX),
    .ext_i(ext_EX),
    .pc_op_o(pc_op_EX),
    .npc_o(npc_EX)
);

ALU u_alu(
    .alu_op(alu_op_EX),
    .c(alu_c_EX),
    .eq(eq_EX),
    .lt(lt_EX),
    .ltu(ltu_EX),
    // alua_sel
    .alua_sel(alua_sel_EX),
    .rD1(rD1_EX),
    .pc(pc_EX),
    // alub_sel
    .alub_sel(alub_sel_EX),
    .rD2(rD2_EX),
    .ext(ext_EX)
);

EX_MEM u_ex_mem(
    .clk(clk),
    .rst_n(rst_n),
    .pause(pause_EX_MEM),
    .flush(flush_EX_MEM),

    .rf_we_i(rf_we_EX),
    .wd_sel_i(wd_sel_EX),
    .wen_i(wen_EX),
    .sd_sel_i(sd_sel_EX),
    .ld_sel_i(ld_sel_EX),
    .pc4_i(pc4_EX),
    .ext_i(ext_EX),
    .alu_c_i(alu_c_EX),
    .rD2_i(rD2_EX),
    .wR_i(wR_EX),

    .rf_we_o(rf_we_MEM),
    .wd_sel_o(wd_sel_MEM),
    .wen_o(wen_MEM),
    .sd_sel_o(sd_sel_MEM),
    .ld_sel_o(ld_sel_MEM),
    .pc4_o(pc4_MEM),
    .ext_o(ext_MEM),
    .alu_c_o(alu_c_MEM),
    .rD2_o(rD2_MEM),
    .wR_o(wR_MEM),

    .debug_pc_i         (pc_EX),
    .debug_pc_o         (debug_pc_MEM),
    .debug_have_inst_i  (debug_have_inst_EX),
    .debug_have_inst_o  (debug_have_inst_MEM)
);

// **********MEM**********

// wire dram_clk = ~clk;
// DRAM u_dram(
//     .clk(dram_clk),
//     .dram_we(wen_MEM),
//     .sd_sel(sd_sel_MEM),
//     .ld_sel(ld_sel_MEM),
//     .addr(alu_c_MEM),
//     .wdin(rD2_MEM),
//     .rd(rd_MEM)
// );

MEM_WB u_mem_wb(
    .clk(clk),
    .rst_n(rst_n),
    .pause(pause_MEM_WB),
    .flush(flush_MEM_WB),

    .rf_we_i(rf_we_MEM),
    .wR_i(wR_MEM),
    .wd_sel_i(wd_sel_MEM),
    .pc4_i(pc4_MEM),
    .ext_i(ext_MEM),
    .alu_c_i(alu_c_MEM),
    .rd_i(rd_MEM),

    .rf_we_o(rf_we_WB),
    .wR_o(wR_WB),
    .wD_o(wD_WB),

    .debug_pc_i         (debug_pc_MEM),
    .debug_pc_o         (debug_pc_WB),
    .debug_have_inst_i  (debug_have_inst_MEM),
    .debug_have_inst_o  (debug_have_inst_WB)
);

endmodule